package task

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
)

var webSocket map[string]*ConnectInfo

type WebSocketHandler struct {
	wg    websocket.Upgrader
	flows map[string]string
}

type ConnectInfo struct {
	LoginId string `json:"loginId"`
	GroupId string `json:"groupId"`
	conn    *websocket.Conn
}

func NewWebSocketHandler(flows map[string]string) *WebSocketHandler {
	m := new(WebSocketHandler)
	m.wg = websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	m.flows = flows
	return m
}

func (m *WebSocketHandler) Connect(c *gin.Context) {
	conn, err := m.wg.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Println("WEB Socket绑定失败：", err)
		return
	}
	_, data, err := conn.ReadMessage()
	if err != nil {
		log.Println("WEB Socket读取数据失败：", err)
		conn.Close()
		return
	}
	info := new(ConnectInfo)
	err = json.Unmarshal(data, info)
	if err != nil {
		log.Println("WEB Socket解稀数据失败：", err)
		conn.Close()
		return
	}
	connInfo := webSocket[info.LoginId]
	if connInfo != nil {
		connInfo.conn.Close()
		delete(webSocket, info.LoginId)
	}
	webSocket[info.LoginId] = connInfo
	go m.handler(info.LoginId)
}

func (m *WebSocketHandler) handler(id string) {
	cli := webSocket[id]
	defer func() {
		cli.conn.Close()
		delete(webSocket, id)
	}()

	for {
		service := NewWebSocketService(cli.conn)
		input, err := service.Read()
		if err != nil {
			continue
		}
		service.input = input
		flowData := input["flowId"]
		if flowData == nil {
			service.Write([]byte("参数flowId任务流程不能为空！"))
			continue
		}
		flow, err := NewFlowTask(nil, flowData.(string))
		if err != nil {
			service.Write([]byte("flowId任务流程未找到！"))
			continue
		}
		service.flow = flow
		list := flow.Data.NodeList
		err = flow.Next(list[0].Id)
		if err != nil {
			service.Write([]byte(err.Error()))
			continue
		}
		service.End()
	}
}

type WebSocketService struct {
	conn  *websocket.Conn
	flow  *FlowTask
	input map[string]interface{}
}

func NewWebSocketService(conn *websocket.Conn) *WebSocketService {
	m := new(WebSocketService)
	m.conn = conn
	return m
}

func NewWebSocketPush(flow *FlowTask, node *Node) error {
	groupId := node.Content["groupId"]
	loginId := node.Content["loginId"]
	clis := make(map[string]*ConnectInfo, 0)
	if groupId == "" && loginId == "" {
		clis = webSocket
	}
	for k, cli := range webSocket {
		if loginId != "" {
			clis[k] = cli
			break
		} else if groupId == cli.GroupId {
			clis[k] = cli
		}
	}

	for _, cli := range clis {
		result := flow.BindInput(node.Params)
		cli.conn.WriteJSON(result)
	}
	return nil
}

func (m *WebSocketService) End() {
	m.flow.wg.Wait()
	var node Node
	for _, n := range m.flow.Data.NodeList {
		if n.NodeType == "END" {
			node = n
			break
		}
	}

	successCode := node.Content["successCode"]
	dataKey := node.Content["dataKey"]
	dataType := node.Content["dataType"]
	result := m.flow.BindInput(node.Params)
	switch dataType {
	case "bytes":
		for _, v := range result {
			bs, ok := v.([]byte)
			if !ok {
				bs, _ := json.Marshal(gin.H{"code": "5000", "msg": "响应参数绑定与响应类型不匹配"})
				m.Write(bs)
				return
			}
			m.Write(bs)
		}
	default:
		if dataKey != "" {
			bs, _ := json.Marshal(gin.H{"code": successCode, "msg": "成功", dataKey: result})
			m.Write(bs)
		} else if len(result) == 1 {
			for k, v := range result {
				if dataType == "string" {
					m.Write([]byte(v.(string)))
				} else {
					bs, _ := json.Marshal(gin.H{"code": successCode, "msg": "成功", k: v})
					m.Write(bs)
				}
				break
			}
		} else {
			bs, _ := json.Marshal(result)
			m.Write(bs)
		}
	}
}

func (m *WebSocketService) Read() (map[string]interface{}, error) {
	mt, data, err := m.conn.ReadMessage()
	if err != nil {
		fmt.Println("WEB Socket读操作失败", err)
		return nil, err
	}
	switch mt {
	case websocket.TextMessage:
		input := make(map[string]interface{}, 0)
		err := json.Unmarshal(data, &input)
		log.Println("WEB Socket解稀数据失败：", err)
		return input, err
	}
	return nil, nil
}

func (m *WebSocketService) Write(data []byte) {
	m.Write(data)
}
